﻿
using Microsoft.VisualStudio.TestTools.UnitTesting;
using static FlyIL.OperandMaker;
using static FlyIL.AssemblerRegisters;
using FlyIL.Advance;



namespace FlyIL.Optimizer.Tests
{

    [TestClass()]
    class Class1
    {



        ///  以下 代码 来源自  vtil 源码 


        [TestMethod()]
        public void test_istack_ref_substitution_pass()
        {
            //// mov eax,esp
            //block->mov(reg_eax, vtil::REG_SP);
            //// sub eax, 4
            //block->sub(reg_eax, vtil::arch::size);
            //// mov [eax+0], 1
            //block->str(reg_eax, 0, (uintptr_t)1);
            //block->vexit(0ull); // marks the end of a basic_block

            Context vcontext = new Context(false);
            vcontext.Make().mov(R1D, Vip);
            vcontext.Make().sub(R1D, 4);
            vcontext.Make().mov(_dword_[R1W + 0], 1);

            /// 优化后这条指令 会改成  mov dowrd_ptr[ vsp - 4] , 1 

        }


        [TestMethod()]
        public void test_stack_propagation_pass()
        {
            //// mov [esp+0], 0x1234
            //block->str(vtil::REG_SP, 0, (uintptr_t)0x1234);
            //// mov eax, [esp+0]
            //block->ldd(reg_eax, vtil::REG_SP, 0);
            //block->vexit(0ull); // marks the end of a basic_block

            Context vcontext = new Context(false);
            vcontext.Make().mov(_dword_[Vip + 0], 0x1234);
            vcontext.Make().mov(R1D, _dword_[Vip + 0]);



        }

        [TestMethod()]
        public void test_dead_code_elimination_pass()
        {
            //block->mov(reg_eax, (uintptr_t)1);
            //block->mov(reg_eax, (uintptr_t)2);
            //block->vexit(0ull); // marks the end of a basic_block

            //Vcontext vcontext = new Vcontext(false);
            //vcontext.Make().mov(R1D, 1);
            //vcontext.Make().mov(R1D, 2);

            //new 死代码化简().Simplify(vcontext);

        }


        [TestMethod()]
        public void test_mov_propagation_pass()
        {
            //// mov eax, 0x1
            //block->mov(reg_eax, (uintptr_t)1);
            //// mov ebx, eax
            //block->mov(reg_ebx, reg_eax);
            //block->vexit(0ull); // marks the end of a basic_block

            Context vcontext = new Context(false);
            vcontext.Make().mov(R1D, 1);
            vcontext.Make().mov(R1D, R1D);

        }



        [TestMethod()]
        public void test_register_renaming_pass()
        {
            //// mov eax, 1
            //block->mov(reg_eax, (uintptr_t)1);
            //// mov ebx, eax
            //block->mov(reg_ebx, reg_eax);
            //// mov [esp+0], ebx
            //block->str(vtil::REG_SP, 0, reg_ebx);
            //block->mov(reg_eax, (uintptr_t)1);
            //block->mov(reg_ebx, (uintptr_t)1);
            //block->vexit(0ull); // marks the end of a basic_block

            Context vcontext = new Context(false);
            vcontext.Make().mov(R1D, 1);
            vcontext.Make().mov(R4D, R1D);
            vcontext.Make().mov(_dword_[Vip + 0], R4D);
            vcontext.Make().mov(R1D, 1);
            vcontext.Make().mov(R4D, 1);
        }



        [TestMethod()]
        public void test_symbolic_rewrite_pass()
        {
            //// mov eax, 1
            //block->mov(reg_eax, (uintptr_t)1);
            //// mov ebx, eax
            //block->mov(reg_ebx, reg_eax);
            //// mov[esp+0], ebx
            //block->str(vtil::REG_SP, 0, reg_ebx);
            //block->mov(reg_eax, (uintptr_t)1);
            //block->mov(reg_ebx, (uintptr_t)1);
            //block->vexit(0ull); // marks the end of a basic_block
            Context vcontext = new Context(false);
            vcontext.Make().mov(R1D, 1);
            vcontext.Make().mov(R2D, R1D);
            vcontext.Make().mov(_dword_[Vip + 0], R2D);
            vcontext.Make().mov(R1D, 1);
            vcontext.Make().mov(R2D, 1);
        }

        [TestMethod()]
        public void test_dead_code_elimination_pass2()
        {

        }



        [TestMethod()]
        public void test_Simplification()
        {
            //block->mov(eax, 0);

            //for (int i = 0; i < 2; ++i)
            //{
            //    block->add(eax, 13);
            //    block->nop();
            //    block->sub(eax, 12);
            //    block->nop();
            //    block->add(eax, 14);
            //    block->mov(eax, eax);
            //    block->sub(eax, eax);
            //    block->bxor(eax, i);
            //    block->push(eax);
            //}

            //block->vpinr(eax);  // pin register eax as read so it doesn't get optimized away
            //block->vexit(0ull); // marks the end of a basic_block

        }

        [TestMethod()]
        public void test_bblock_thunk_removal_pass()
        {
            //auto block1 = vtil::basic_block::begin((uintptr_t)0x1000);
            //auto rtn = block1->owner;
            //{
            //    // 0x1000: js eflags@11:1 0x2000, 0x3000
            //    block1->js(vtil::REG_FLAGS.select(1, 11), (uintptr_t)0x2000, (uintptr_t)0x3000);
            //}
            //auto block2 = block1->fork((uintptr_t)0x2000);
            //{
            //    // 0x2000: jmp 0x4000
            //    block2->jmp((uintptr_t)0x4000);
            //    block2->fork((uintptr_t)0x4000);
            //}
            //auto block3 = block1->fork((uintptr_t)0x3000);
            //{
            //    // 0x3000: jmp 0x4000
            //    block3->jmp((uintptr_t)0x4000);
            //    block3->fork((uintptr_t)0x4000);
            //}
            //auto block4 = rtn->get_block((uintptr_t)0x4000);
            //{
            //    // 0x4000: jmp 0x5000
            //    block4->jmp((uintptr_t)0x5000);
            //    block4->fork((uintptr_t)0x5000);
            //}
            //auto block5 = rtn->get_block((uintptr_t)0x5000);
            //{
            //    // 0x5000: vexit 0
            //    block5->vexit((uintptr_t)0);
            //}
        }

        [TestMethod()]
        public void test_branch_correction_pass()
        {
            //{
            //    block1->mov(reg_flags.select(1, 0), 0x0);
            //    block1->js(reg_flags.select(1, 0), (uintptr_t)0x2000, (uintptr_t)0x3000);
            //}

            //auto block2 = block1->fork(0x2000);
            //{
            //    block2->push(reg_flags); //dummy pin
            //    block2->vexit(0ull);     // marks the end
            //}

            //auto block3 = block1->fork(0x3000);
            //{
            //    block3->push(reg_flags); //dummy pin
            //    block3->vexit(0ull);     // marks the end
            //}
        }



    }
}
